﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web.Mvc;
using Actya.Core;
using Actya.Core.Infrastructure;
using Actya.Core.SiteStructure;
using Actya.Core.Widgets;
using Actya.Web.Infrastructure.AntiForgery;
using Actya.Web.Mvc.Helpers;
using Actya.Web.ViewModels.Admin;

namespace Actya.Web.Controllers.CmsAdmin
{
	[Authorize(Roles = RoleNames.CmsAdministrators)]
    public class LayoutsController : Controller
    {
    	private readonly ICmsContext _cmsContext;
    	private readonly ISiteService _siteService;
    	private readonly IPageService _pageService;
		private readonly IWidgetService _widgetService;

    	public LayoutsController(ICmsContext cmsContext, ISiteService siteService, IPageService pageService, IWidgetService widgetService)
    	{
    		_cmsContext = cmsContext;
    		_widgetService = widgetService;
    		_siteService = siteService;
    		_pageService = pageService;
    	}

    	public ActionResult Index()
        {
            return View(this._cmsContext.Site);
        }

		public ActionResult Create()
		{
			var viewModel = new EditLayoutViewModel();
			SetLookupLists(viewModel);
			return View("Edit", viewModel);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult Create(EditLayoutViewModel viewModel)
		{
			var site = _cmsContext.Site;
			if (ModelState.IsValid)
			{
				try
				{
					this._siteService.AddPageLayoutToSite(site, viewModel.PageLayout);
					this.ShowMessage(MessageType.Success, string.Format("Page layout is created successfully."), true);
					return RedirectToAction("Index");
				}
				catch (Exception ex)
				{
					this.ShowMessage(MessageType.Error, ex.Message);
				}
			}
			SetLookupLists(viewModel);
			return View("Edit", viewModel);
		}

		public ActionResult Update(string id)
		{
			var viewModel = new EditLayoutViewModel();
			viewModel.PageLayout = _cmsContext.Site.PageLayouts.Single(pl => pl.Id == id);
			SetLookupLists(viewModel);
			return View("Edit", viewModel);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult Update(EditLayoutViewModel viewModel)
		{
			if (ModelState.IsValid)
			{
				var site = _cmsContext.Site;

				try
				{
					this._siteService.UpdatePageLayout(site, viewModel.PageLayout);
					this.ShowMessage(MessageType.Success, string.Format("Page layout is updated successfully."), true);
					return RedirectToAction("Index");
				}
				catch (Exception ex)
				{
					this.ShowMessage(MessageType.Error, ex.Message);
				}
			}
			SetLookupLists(viewModel);
			return View("Edit", viewModel);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult Delete(string id)
		{
			var pageLayout = _cmsContext.Site.PageLayouts.Single(pl => pl.Id == id);
			if (_pageService.FindPageByLayout(pageLayout.Id).Any())
			{
				this.ShowMessage(MessageType.Error, "Can't delete page layout because there are pages that use this layout.", true);
			}
			else
			{
				try
				{
					_cmsContext.Site.PageLayouts.Remove(pageLayout);
					this._siteService.UpdateSite(_cmsContext.Site);
					this.ShowMessage(MessageType.Success, string.Format("The page layout '{0}' is deleted successfully.", pageLayout.Name), true);
				}
				catch (Exception ex)
				{
					this.ShowMessage(MessageType.Error, ex.Message, true);
				}				
			}
			return RedirectToAction("Index");
		}

		public ActionResult Widgets(string id)
		{
			var site = _cmsContext.Site;
			var pageLayout = site.PageLayouts.Single(pl => pl.Id == id);
			var theme = !String.IsNullOrEmpty(pageLayout.Theme) ? site.GetThemeByName(pageLayout.Theme) : site.GetThemeByName(site.DefaultTheme);
			var widgetTypesbyWidgetIds = _cmsContext.GetWidgetsForPageLayout(pageLayout).ToDictionary(w => w.Id, w => w.WidgetTypeName);
			return View(new LayoutWidgetsViewModel(pageLayout, theme.ContentRegions, site.WidgetTypes, widgetTypesbyWidgetIds));
		}

		[HttpPost]
		[AjaxValidateAntiForgeryToken]
		public ActionResult CreateWidget(string id, string widgetName, string contentRegion)
		{
			var site = _cmsContext.Site;
			var pageLayout = site.PageLayouts.Single(pl => pl.Id == id);
			var widgetType = site.WidgetTypes.Single(wt => wt.Name == widgetName);

			try
			{
				var widget = _widgetService.CreateWidget(widgetType);
				if (! pageLayout.Widgets.ContainsKey(contentRegion))
				{
					pageLayout.Widgets.Add(contentRegion, new List<string>());
				}
				pageLayout.Widgets[contentRegion].Add(widget.Id);
				_siteService.UpdateSite(site);
				this.ShowMessage(MessageType.Success, string.Format("The widget is added to the layout. You can now start editing"));
				return Json(widget);
			}
			catch (Exception ex)
			{
				this.ShowMessage(MessageType.Error, ex.Message);
			}

			return new EmptyResult();
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult DeleteWidget(string id, string widgetId)
		{
			var site = _cmsContext.Site;
			var pageLayout = site.PageLayouts.Single(pl => pl.Id == id);
			try
			{
				var widget = _widgetService.GetWidgetById(widgetId);
				this._widgetService.Delete(widget);
				var contentRegionWithWidget = pageLayout.Widgets.Single(cr => cr.Value.Any(w => w == widgetId));
				contentRegionWithWidget.Value.Remove(widgetId);
				this._siteService.UpdateSite(site);
			}
			catch (Exception ex)
			{
				this.ShowMessage(MessageType.Error, ex.Message, true);
			}
			return RedirectToAction("Widgets", new {id});
		}

		[HttpPost]
		public ActionResult SortWidgets(string layoutId, string contentRegion, string[] sortedWidgetIds)
		{
			var site = _cmsContext.Site;
			var pageLayout = site.PageLayouts.Single(pl => pl.Id == layoutId);
			try
			{
				pageLayout.Widgets[contentRegion] = new List<string>(sortedWidgetIds);
				_siteService.UpdateSite(site);
				this.ShowMessage(MessageType.Success, string.Format("The widgets are ordered successfully."));
				return Json("Success");
			}
			catch (Exception ex)
			{
				this.ShowMessage(MessageType.Error, ex.Message);
			}
			return new EmptyResult();
		}

		private void SetLookupLists(EditLayoutViewModel viewModel)
		{
			viewModel.PageTypes = _cmsContext.Site.PageTypes;
			viewModel.Themes = _cmsContext.Site.Themes.Select(t => t.Name).ToArray();
		}
    }
}
